home *** CD-ROM | disk | FTP | other *** search
/ Turnbull China Bikeride / Turnbull China Bikeride - Disc 2.iso / STUTTGART / TEX-UTIL / DVIPS_55 / dvips / src / c / emspecial < prev    next >
Text File  |  1994-05-06  |  35KB  |  1,485 lines

  1. /*
  2.  *   emspecial.c
  3.  *   This routine handles the emTeX special commands.
  4.  */
  5. #include "dvips.h" /* The copyright notice in that file is included too!*/
  6.  
  7. /* extern int atoi(); */ 
  8. extern FILE *search();
  9. /* extern char *getenv(); */
  10. /*
  11.  *   These are the external routines called:
  12.  */
  13. /**/
  14. extern void hvpos() ;
  15. extern void cmdout() ;
  16. extern void mhexout() ;
  17. extern void nlcmdout() ;
  18. extern void newline() ;
  19. extern void floatout() ;
  20. extern void numout() ;
  21. extern void error() ;
  22. extern void specerror() ;
  23. extern char errbuf[] ;
  24. extern shalfword linepos;
  25. extern FILE *bitfile;
  26. extern int actualdpi ;
  27. extern int vactualdpi ;
  28. extern integer hh, vv;
  29. /*extern char *figpath ; */
  30. extern int prettycolumn ;
  31. extern int quiet;
  32. extern Boolean disablecomments ;
  33.  
  34. #ifdef DEBUG
  35. extern integer debug_flag;
  36. #endif
  37.  
  38.  
  39. #ifdef EMTEX
  40. /* emtex specials, added by rjl */
  41.  
  42. #define EMMAX 1613 /* maximum number of emtex special points */
  43. #define TRUE 1
  44. #define FALSE 0
  45.  
  46. /*
  47.  *   We define these seek constants if they don't have their
  48.  *   values already defined.
  49.  */
  50. #ifndef SEEK_SET
  51. #define SEEK_SET (0)
  52. #endif
  53. #ifndef SEEK_END
  54. #define SEEK_END (2)
  55. #endif
  56.  
  57. struct empt {
  58.    shalfword point;
  59.    integer x, y;
  60. };
  61.  
  62. struct empt *empoints = NULL;
  63. boolean emused = FALSE;  /* true if em points used on this page */
  64. integer emx, emy;
  65.  
  66. struct emunit {
  67.    char *unit;
  68.    float factor;
  69. };
  70. struct emunit emtable[] = {
  71.   {"pt",72.27},
  72.   {"pc",72.27/12},
  73.   {"in",1.0},
  74.   {"bp",72.0},
  75.   {"cm",2.54},
  76.   {"mm",25.4},
  77.   {"dd",72.27/(1238/1157)},
  78.   {"cc",72.27/12/(1238/1157)},
  79.   {"sp",72.27*65536},
  80.   {"",0.0}
  81. };
  82.  
  83.  
  84. /* clear the empoints array if necessary */
  85. void
  86. emclear()
  87. {
  88. int i;
  89.    if (emused && empoints)
  90.       for (i=0; i<EMMAX; i++)
  91.          empoints[i].point = 0;
  92.    emused = FALSE ;
  93. }
  94.  
  95. /* put an empoint into the empoints array */
  96. struct empt *emptput(point, x, y)
  97. shalfword point;
  98. integer x, y;
  99. {
  100. int i, start;
  101.  
  102.    emused = TRUE;
  103.    start = point % EMMAX;
  104.    i = start;
  105.    while ( empoints[i].point != 0 ) {
  106.       if ( empoints[i].point == point )
  107.          break;
  108.       i++;
  109.       if (i >= EMMAX)
  110.          i = 0;
  111.       if (i == start) {
  112.      sprintf(errbuf,"!Too many em: special points");
  113.      specerror(errbuf);
  114.       }
  115.    }
  116.  
  117.    empoints[i].point = point;
  118.    empoints[i].x = x;
  119.    empoints[i].y = y;
  120.    return(&empoints[i]);
  121. }
  122.  
  123. /* get an empoint from the empoints array */
  124. struct empt *emptget(point)
  125. shalfword point;
  126. {
  127. int i, start;
  128.  
  129.    start = point % EMMAX;
  130.    i = start;
  131.    if (emused == TRUE)
  132.       while ( empoints[i].point != 0 ) {
  133.          if (empoints[i].point == point)
  134.             return(&empoints[i]);
  135.          i++;
  136.          if (i >= EMMAX)
  137.             i = 0;
  138.          if (i == start)
  139.             break;
  140.       }
  141.    sprintf(errbuf,"!em: point %d not defined",point);
  142.    specerror(errbuf);
  143.    return(NULL); /* never returns due to error */
  144. }
  145.  
  146.  
  147. /* convert width into dpi units */
  148. float emunits(width,unit)
  149. float width;
  150. char *unit;
  151. {
  152. struct emunit *p;
  153.     for (p=emtable; *(p->unit)!='\0'; p++) {
  154.        if (strcmp(p->unit,unit)==0)
  155.         return( width * actualdpi / p->factor );
  156.     }
  157.     return (-1.0); /* invalid unit */
  158. }
  159.  
  160. /* The main routine for \special{em:graph ...} called from dospecial.c */
  161. /* the line cut parameter is not supported (and is ignored) */
  162.  
  163. void emspecial(p)
  164. char *p ;
  165. {
  166. float emwidth, emheight;
  167. shalfword empoint1, empoint2;
  168. struct empt *empoint;
  169. char emunit[3];
  170. char emstr[80];
  171. char *emp;
  172. void emgraph();
  173.  
  174.         hvpos() ;
  175.     for (emp = p+3; *emp && isspace(*emp); emp++); /* skip blanks */
  176.     if (strncmp(emp, "linewidth", 9) == 0) {
  177.        /* code for linewidth */
  178.        for (emp = emp+9; *emp && isspace(*emp); emp++); /* skip blanks */
  179.        sscanf(emp, "%f%2s", &emwidth, emunit);
  180.        emwidth = emunits(emwidth,emunit);
  181.        if (emwidth!=-1.0) {
  182.           sprintf(emstr,"%.1f setlinewidth", emwidth);
  183.           cmdout(emstr);
  184. #ifdef DEBUG
  185.    if (dd(D_SPECIAL))
  186.       (void)fprintf(stderr, "em special: Linewidth set to %.1f dots\n", 
  187.         emwidth) ;
  188. #endif
  189.        } else {
  190.           sprintf(errbuf,"Unknown em: special width");
  191.           specerror(errbuf);
  192.        }
  193.     }
  194.         else if (strncmp(emp, "moveto", 6) == 0) {
  195. #ifdef DEBUG
  196.    if (dd(D_SPECIAL))
  197. #ifdef SHORTINT
  198.       (void)fprintf(stderr, "em special: moveto %ld,%ld\n", hh, vv);
  199. #else
  200.       (void)fprintf(stderr, "em special: moveto %d,%d\n", hh, vv);
  201. #endif
  202. #endif
  203.            emx = hh;
  204.            emy = vv;
  205.         }
  206.         else if (strncmp(emp, "lineto", 6) == 0) {
  207. #ifdef DEBUG
  208.    if (dd(D_SPECIAL))
  209. #ifdef SHORTINT
  210.       (void)fprintf(stderr, "em special: lineto %ld,%ld\n", hh, vv);
  211. #else
  212.       (void)fprintf(stderr, "em special: lineto %d,%d\n", hh, vv);
  213. #endif
  214. #endif
  215.        cmdout("np");
  216.        numout(emx);
  217.        numout(emy);
  218.        cmdout("a");
  219.        numout(hh);
  220.        numout(vv);
  221.        cmdout("li");
  222.        cmdout("st");
  223.            emx = hh;
  224.            emy = vv;
  225.         }
  226.     else if (strncmp(emp, "point", 5) == 0) {
  227.            if (empoints == NULL) {
  228.               empoints = 
  229.               (struct empt *)mymalloc((integer)EMMAX * sizeof(struct empt)) ;
  230.               emused = TRUE;
  231.               emclear();
  232.            }
  233.        for (emp = emp+5; *emp && isspace(*emp); emp++); /* skip blanks */
  234.            empoint1 = (shalfword)atoi(emp);
  235.            empoint = emptput(empoint1,hh,vv);
  236. #ifdef DEBUG
  237.    if (dd(D_SPECIAL))
  238. #ifdef SHORTINT
  239.       (void)fprintf(stderr, "em special: Point %d is %ld,%ld\n",
  240. #else
  241.       (void)fprintf(stderr, "em special: Point %d is %d,%d\n",
  242. #endif
  243.         empoint->point, empoint->x, empoint->y) ;
  244. #endif
  245.     }
  246.     else if (strncmp(emp, "line", 4) == 0) {
  247.        for (emp = emp+4; *emp && isspace(*emp); emp++); /* skip blanks */
  248.            empoint1 = (shalfword)atoi(emp);
  249.        for (; *emp && isdigit(*emp); emp++); /* skip point 1 */
  250.        if ( *emp && strchr("hvp",*emp)!=0 )
  251.           emp++;  /* skip line cut */
  252.        for (; *emp && isspace(*emp); emp++); /* skip blanks */
  253.        if ( *emp && (*emp==',') )
  254.           emp++; /*  skip comma separator */
  255.        for (; *emp && isspace(*emp); emp++); /* skip blanks */
  256.            empoint2 = (shalfword)atoi(emp);
  257.        for (; *emp && isdigit(*emp); emp++); /* skip point 2 */
  258.        if ( *emp && strchr("hvp",*emp)!=0 )
  259.           emp++;  /* skip line cut */
  260.        for (; *emp && isspace(*emp); emp++); /* skip blanks */
  261.        if ( *emp && (*emp==',') )
  262.           emp++; /*  skip comma separator */
  263.        emwidth = -1.0;
  264.        emunit[0]='\0';
  265.        sscanf(emp, "%f%2s", &emwidth, emunit);
  266.        emwidth = emunits(emwidth,emunit);
  267. #ifdef DEBUG
  268.    if (dd(D_SPECIAL))
  269.       (void)fprintf(stderr, "em special: Line from point %d to point %d\n",
  270.         empoint1, empoint2) ;
  271. #endif
  272.        cmdout("np");
  273.        if (emwidth!=-1.0) {
  274. #ifdef DEBUG
  275.    if (dd(D_SPECIAL))
  276.    (void)fprintf(stderr,"em special: Linewidth temporarily set to %.1f dots\n", 
  277.         emwidth) ;
  278. #endif
  279.            strcpy(emstr,"currentlinewidth");
  280.            cmdout(emstr);
  281.             sprintf(emstr,"%.1f setlinewidth", emwidth);
  282.             cmdout(emstr);
  283.        }
  284.            empoint = emptget(empoint1);
  285.        numout(empoint->x);
  286.        numout(empoint->y);
  287.        cmdout("a");
  288.            empoint = emptget(empoint2);
  289.        numout(empoint->x);
  290.        numout(empoint->y);
  291.        cmdout("li");
  292.        cmdout("st");
  293.        if (emwidth!=-1.0) {
  294.            strcpy(emstr,"setlinewidth");
  295.            cmdout(emstr);
  296.        }
  297.     }
  298.     else if (strncmp(emp, "message", 7) == 0) {
  299.            (void)fprintf(stderr, "em message: %s\n", emp+7) ;
  300.     }
  301.     else if (strncmp(emp, "graph", 5) == 0) {
  302.        int i;
  303.        for (emp = emp+5; *emp && isspace(*emp); emp++); /* skip blanks */
  304.        for (i=0; *emp && !isspace(*emp) && !(*emp==',') ; emp++)
  305.           emstr[i++] = *emp; /* copy filename */
  306.        emstr[i] = '\0';
  307.        /* now get optional width and height */
  308.        emwidth = emheight = -1.0;    /* no dimension is <= 0 */
  309.        for (; *emp && ( isspace(*emp) || (*emp==',') ); emp++)
  310.           ;  /* skip blanks and comma */
  311.        if (*emp) {
  312.           sscanf(emp, "%f%2s", &emwidth, emunit); /* read width */
  313.           emwidth = emunits(emwidth,emunit); /* convert to pixels */
  314.           for (; *emp && (*emp=='.'||isdigit(*emp)||isalpha(*emp)); emp++)
  315.              ; /* skip width dimension */
  316.           for (; *emp && ( isspace(*emp) || (*emp==',') ); emp++)
  317.              ;  /* skip blanks and comma */
  318.           if (*emp) {
  319.              sscanf(emp, "%f%2s", &emheight, emunit); /* read height */
  320.              emheight = emunits(emheight,emunit)*vactualdpi/actualdpi;
  321.           }
  322.        }
  323.        if (emstr[0]) {
  324.           emgraph(emstr,emwidth,emheight);
  325.        }
  326.        else {
  327.               (void)fprintf(stderr, "em:graph: no file given\n") ;
  328.        }
  329.     }
  330.     else {
  331.            sprintf(errbuf, 
  332.           "Unknown em: command (%s) in \\special will be ignored", p);
  333.            specerror(errbuf) ;
  334.     }
  335.     return;
  336.    }
  337.  
  338.  
  339. /* em:graph routines */
  340.  
  341. /* The graphics routines currently decode 3 types of IBM-PC based graphics   */
  342. /* files: .pcx, .bmp, .msp. The information on the formats has occasionally  */
  343. /* been sketchy, and subject to interpretation. I have attempted to implement*/
  344. /* these routines to correctly decode the graphics file types mentioned.     */
  345. /* The compressed .bmp file type has not been tested fully due to a lack of  */
  346. /* test files.                                                               */
  347. /*                                                                           */
  348. /* The method of reading in the headers of the binary files is ungainly, but */
  349. /* portable. Failure to use a byte by byte read and convert method will      */
  350. /* result in portability problems. Specifically there is no requirement that */
  351. /* elements of a C structure be contiguous, only that they have an ascending */
  352. /* order of addresses.                                                       */
  353. /*                                                                           */
  354. /* The current implementations of the graphics format to postscript          */
  355. /* conversion are not the most efficient possible. Specifically: color       */
  356. /* formats are converted to RGB ratios prior to using a simple thresholding  */
  357. /* method to determine if the postscript bit is to be set. The thresholding  */
  358. /* method is compabible with that used in emtex's drivers.                   */
  359. /*                                                                           */
  360. /* Please send bug reports relating to the em:graph routines to:             */
  361. /*                maurice@bruce.cs.monash.edu.au                             */
  362. /*                                                                           */
  363. /* My thanks to Russell Lang for his assistance with the implementation of   */
  364. /* these routines in a manner compatible with dvips and for the optimization */
  365. /* of some routines.                                                         */
  366. /*                                                                           */
  367. /*                                                   Maurice Castro          */
  368. /*                                                   8 Oct 92                */
  369.  
  370. /* Routines to read binary numbers from IBM PC file types */
  371. integer readinteger(f)
  372. FILE *f;
  373. {
  374.    integer i;
  375.    int r;
  376.  
  377.    i = 0;
  378.    for (r = 0; r < 4; r++)
  379.    {
  380.       i = i |  ( ((integer) fgetc(f)) << (8*r) );
  381.    }
  382.    return(i);
  383. }
  384.  
  385. halfword readhalfword(f)
  386. FILE *f;
  387. {
  388.    halfword i;
  389.    int r;
  390.  
  391.    i = 0;
  392.    for (r = 0; r < 2; r++)
  393.    {
  394.      i = i |  ( ((halfword) fgetc(f)) << (8*r) );
  395.    }
  396.    return(i);
  397. }
  398.  
  399. #define readquarterword(f) ((unsigned char)fgetc(f))
  400. #define tobyte(x) ((x/8) + (x%8 ? 1 : 0))
  401.  
  402. /* These routines will decode PCX files produced by Microsoft 
  403.  * Windows Paint.  Other programs may not produce files which
  404.  * will be successfully decoded, most notably version 1.xx of
  405.  * PC Paint. */
  406.  
  407. /*
  408.  *   Type declarations.  integer must be a 32-bit signed; shalfword must
  409.  *   be a sixteen-bit signed; halfword must be a sixteen-bit unsigned;
  410.  *   quarterword must be an eight-bit unsigned.
  411.  */
  412. typedef struct 
  413. {
  414.     quarterword man;
  415.     quarterword ver;
  416.     quarterword enc;
  417.     quarterword bitperpix;
  418.     halfword xmin;
  419.     halfword ymin;
  420.     halfword xmax;
  421.     halfword ymax;
  422.     halfword hres;
  423.     halfword vres;
  424.     quarterword pal[48];
  425.     quarterword reserved;
  426.     quarterword colorplanes;
  427.     halfword byteperline;
  428.     halfword paltype;
  429.     quarterword fill[58];
  430. } PCXHEAD; 
  431.  
  432. int PCXreadhead(pcxf, pcxh)
  433. FILE *pcxf;
  434. PCXHEAD *pcxh;
  435. {
  436.     pcxh->man = readquarterword(pcxf);
  437.     pcxh->ver = readquarterword(pcxf);
  438.     pcxh->enc = readquarterword(pcxf);
  439.     pcxh->bitperpix = readquarterword(pcxf);
  440.     pcxh->xmin = readhalfword(pcxf);
  441.     pcxh->ymin = readhalfword(pcxf);
  442.     pcxh->xmax = readhalfword(pcxf);
  443.     pcxh->ymax = readhalfword(pcxf);
  444.     pcxh->hres = readhalfword(pcxf);
  445.     pcxh->vres = readhalfword(pcxf);
  446.     fread(pcxh->pal, 1, 48, pcxf);
  447.     pcxh->reserved = readquarterword(pcxf);
  448.     pcxh->colorplanes = readquarterword(pcxf);
  449.     pcxh->byteperline = readhalfword(pcxf);
  450.     pcxh->paltype = readhalfword(pcxf);
  451.     fread(pcxh->fill, 1, 58, pcxf);
  452.  
  453.     if (feof(pcxf))
  454.         return(0);                /* fail */
  455.     if (pcxh->man != 0x0a)
  456.         return(0);                /* fail */
  457.     if (pcxh->enc != 0x1)
  458.         return(0);                /* fail */
  459.     return(1);                    /* success */
  460.     }
  461.  
  462. int PCXreadline(pcxf, pcxbuf, byteperline)
  463. FILE *pcxf;
  464. unsigned char *pcxbuf;
  465. unsigned int byteperline;
  466. {
  467.     int n;
  468.     int c;
  469.     int i;
  470.  
  471.     n = 0;
  472.     memset(pcxbuf,0,byteperline);
  473.     do {
  474.         c = fgetc(pcxf);
  475.         if ((c & 0xc0) == 0xc0) {
  476.             i = c & 0x3f;
  477.             c = fgetc(pcxf) & 0xff;
  478.             while ((i--) && (n < byteperline)) pcxbuf[n++] = c;
  479.         }
  480.         else {
  481.             pcxbuf[n++] = c & 0xff;
  482.         }
  483.     } while (n < byteperline);
  484.     if (c==EOF) n=0;
  485.     return(n);
  486. }
  487.  
  488. void PCXgetpalette(pcxf, pcxh, r, g, b)
  489. FILE *pcxf;
  490. PCXHEAD *pcxh;
  491. unsigned char r[256];
  492. unsigned char g[256];
  493. unsigned char b[256];
  494. {
  495.     int i;
  496.  
  497.     /* clear palette */
  498.     for (i=0; i < 256; i++) {
  499.         r[i] = 0;
  500.         g[i] = 0;
  501.         b[i] = 0;
  502.     }
  503.  
  504.     switch (pcxh->ver) {
  505.         case 0:
  506.             /* version 2.5 of PC Paint Brush */
  507.             for (i=0; i < 16; i++) {
  508.                 r[i] = pcxh->pal[i*3];
  509.                 g[i] = pcxh->pal[i*3+1];
  510.                 b[i] = pcxh->pal[i*3+2];
  511.             }
  512.             break;
  513.         case 2:
  514.             if (pcxh->colorplanes != 1) {
  515.                 /* version 2.8 of PC Paint Brush with valid Palette */
  516.             for (i=0; i < 16; i++) {
  517.                 r[i] = pcxh->pal[i*3];
  518.                 g[i] = pcxh->pal[i*3+1];
  519.                 b[i] = pcxh->pal[i*3+2];
  520.                 }
  521.             }
  522.             else {    /* not sure if this is correct - rjl */
  523.                 /* mono palette */
  524.                 r[0] = 0x00; g[0] = 0x00; b[0] = 0x00;
  525.                 r[1] = 0xff; g[1] = 0xff; b[1] = 0xff;
  526.             }
  527.             break;
  528.         case 3:
  529.             /* version 2.8 of PC Paint Brush with no valid Palette */
  530.             /* either mono or default */
  531.  
  532.             if (pcxh->colorplanes != 1) {
  533.                 /* Color default palette - should be checked */
  534.                 r[0] = 0x00;        g[0] = 0x00;        b[0] = 0x00;
  535.                 r[1] = 0x80;        g[1] = 0x00;         b[1] = 0x00;
  536.                 r[2] = 0x00;         g[2] = 0x80;         b[2] = 0x00;
  537.                 r[3] = 0x80;        g[3] = 0x80;         b[3] = 0x00;
  538.                 r[4] = 0x00;        g[4] = 0x00;         b[4] = 0x80;
  539.                 r[5] = 0x80;        g[5] = 0x00;         b[5] = 0x80;
  540.                 r[6] = 0x00;        g[6] = 0x80;         b[6] = 0x80;
  541.                 r[7] = 0x80;        g[7] = 0x80;         b[7] = 0x80;
  542.                 r[8] = 0xc0;        g[8] = 0xc0;        b[8] = 0xc0;
  543.                 r[9] = 0xff;        g[9] = 0x00;         b[9] = 0x00;
  544.                 r[10] = 0x00;         g[10] = 0xff;         b[10] = 0x00;
  545.                 r[11] = 0xff;         g[11] = 0xff;         b[11] = 0x00;
  546.                 r[12] = 0x00;         g[12] = 0x00;         b[12] = 0xff;
  547.                 r[13] = 0xff;         g[13] = 0x00;         b[13] = 0xff;
  548.                 r[14] = 0x00;         g[14] = 0xff;         b[14] = 0xff;
  549.                 r[15] = 0xff;         g[15] = 0xff;         b[15] = 0xff;
  550.             }
  551.             else {
  552.                 /* mono palette */
  553.                 r[0] = 0x00;        g[0] = 0x00;        b[0] = 0x00;
  554.                 r[1] = 0xff;        g[1] = 0xff;         b[1] = 0xff;
  555.             }
  556.             break;
  557.         case 5:
  558.         default:
  559.             /* version 3.0 of PC Paint Brush or Better */
  560.             fseek(pcxf, -769L, SEEK_END);
  561.             /* if signature byte is correct then read the palette */
  562.             /* otherwise copy the existing palette */
  563.             if (fgetc(pcxf) == 12) {
  564.                 for (i=0; i < 256; i++) {
  565.                     r[i] = fgetc(pcxf);
  566.                     g[i] = fgetc(pcxf);
  567.                     b[i] = fgetc(pcxf);
  568.                 }
  569.             }
  570.             else {
  571.                 for (i=0; i < 16; i++) {
  572.                     r[i] = pcxh->pal[i*3];
  573.                     g[i] = pcxh->pal[i*3+1];
  574.                     b[i] = pcxh->pal[i*3+2];
  575.                 }
  576.             }
  577.             break;
  578.     }
  579. }
  580.  
  581. extern void mhexout() ;
  582.  
  583. void PCXshowpicture(pcxf, wide, high, bytes, cp, bp, r, g, b)
  584. FILE *pcxf;
  585. int wide;
  586. int high;
  587. int bytes;
  588. int cp;
  589. int bp;
  590. unsigned char r[256];
  591. unsigned char g[256];
  592. unsigned char b[256];
  593. {
  594.     int x;
  595.     int y;
  596.     int c;
  597.     unsigned char *rowa[4];                /* row array */
  598.     unsigned char *row;
  599.     int p;
  600.     unsigned char *pshexa;
  601.     int xdiv, xmod, xbit;
  602.     int width;
  603.     int bytewidth;
  604.  
  605.     bytewidth = tobyte(wide);
  606.     width = bytewidth * 8;
  607.  
  608.     /* output the postscript image size preamble */
  609.     cmdout("/picstr ");
  610.     numout((integer)tobyte(wide));
  611.     cmdout("string def");
  612.  
  613.     numout((integer)width);
  614.     numout((integer)high);
  615.     numout((integer)1);
  616.     newline();
  617.  
  618.     cmdout("[");
  619.     numout((integer)width);
  620.     numout((integer)0);
  621.     numout((integer)0);
  622.     numout((integer)-high);
  623.     numout((integer)0);
  624.     numout((integer)0);
  625.     cmdout("]");
  626.  
  627.     nlcmdout("{currentfile picstr readhexstring pop} image");
  628.  
  629.     /* allocate the postscript hex output array */
  630.     pshexa = (unsigned char *) mymalloc((integer)bytewidth);
  631.  
  632.     /* make sure that you start at the right point in the file */
  633.     fseek(pcxf, (long) sizeof(PCXHEAD), SEEK_SET);
  634.  
  635.     /* malloc the lines */
  636.     row = (unsigned char *) mymalloc((integer)bytes * cp);
  637.     for (c = 0; c < cp; c++)
  638.         rowa[c] = row + bytes*c;
  639.  
  640.     for (y = 0; y < high; y++) {
  641.         /* clear the postscript hex array */
  642.         memset(pshexa,0xff,bytewidth);
  643.  
  644.         /* read in all the color planes for a row of pixels */
  645.         PCXreadline(pcxf, rowa[0], bytes*cp);
  646.  
  647.         /* process each pixel */
  648.         for (x = 0; x < wide; x++) {
  649.             /* build up the pixel value from color plane entries */
  650.             p = 0;
  651.             xdiv = x>>3;
  652.             xmod = 7 - (x&7);
  653.             xbit = 1 << xmod;
  654.             switch(bp) {
  655.                 case 1: 
  656.                     for (c = 0; c < cp; c++) {
  657.                         row = rowa[c];
  658.                         p |= ( (unsigned)(row[xdiv] & xbit) >> xmod ) << c;
  659.                     }
  660.                     break;
  661.                 case 4:  /* untested - most programs use 1 bit/pixel, 4 planes */
  662.                     row = rowa[0]; /* assume single plane */
  663.                     p = ( x & 1 ? row[xdiv] : row[xdiv]>>4 ) & 0x0f;
  664.                     break;
  665.                 case 8:
  666.                     row = rowa[0]; /* assume single plane */
  667.                     p = (unsigned) (row[x]);
  668.                     break;
  669.                 default: 
  670.                     fprintf(stderr, "em:graph: Unable to Decode this PCX file\n");
  671.                     return;
  672.             }
  673.             if ((r[p] < 0xff) || (g[p] < 0xff) || (b[p] < 0xff))
  674.                 pshexa[xdiv] &= (~xbit);
  675.             else
  676.                 pshexa[xdiv] |= xbit;
  677.         }
  678.         newline();
  679.         mhexout(pshexa,(long)bytewidth);
  680.     }
  681.     free(pshexa);
  682.     free(rowa[0]);
  683. }
  684.  
  685. void imagehead(filename,wide,high,emwidth,emheight)
  686. char filename[];
  687. int wide, high;
  688. float emwidth, emheight;    /* dimension in pixels */
  689. {
  690.     if (!quiet) {
  691.         if (strlen(filename) + prettycolumn > STDOUTSIZE) {
  692.         fprintf(stderr,"\n");
  693.         prettycolumn = 0;
  694.         }
  695.         (void)fprintf(stderr,"<%s",filename);
  696.         (void)fflush(stderr);
  697.         prettycolumn += 2+strlen(filename);
  698.     }
  699.     hvpos();
  700.     nlcmdout("@beginspecial @setspecial") ;
  701.     if (!disablecomments) {
  702.         cmdout("%%BeginDocument: em:graph");
  703.         cmdout(filename);
  704.         newline();
  705.     }
  706.     /* set the image size */
  707.     if (emwidth <= 0.0)  emwidth = (float)wide;
  708.     if (emheight <= 0.0)  emheight = (float)high;
  709.     floatout(emwidth*72/actualdpi);
  710.     floatout(emheight*72/vactualdpi);
  711.     newline();
  712.     cmdout("scale");
  713. #ifdef DEBUG
  714.     if (dd(D_SPECIAL)) {
  715.       (void)fprintf(stderr, 
  716.         "\nem:graph: %s width  %d pixels scaled to %.1f pixels\n",
  717.         filename, wide, emwidth);
  718.       (void)fprintf(stderr, 
  719.         "em:graph: %s height %d pixels scaled to %.1f pixels\n",
  720.         filename, high, emheight);
  721.        }
  722. #endif
  723. }
  724.  
  725. void imagetail()
  726. {
  727.     if (!disablecomments) {
  728.         (void)fprintf(bitfile, "\n%%%%EndDocument\n") ;
  729.         linepos = 0;
  730.     }
  731.     nlcmdout("@endspecial") ;
  732.     if (!quiet) {
  733.         (void)fprintf(stderr,">");
  734.         (void)fflush(stderr);
  735.     }
  736. }
  737.  
  738. void pcxgraph(pcxf,filename,emwidth,emheight)
  739. FILE *pcxf;
  740. char filename[];
  741. float emwidth, emheight;    /* dimension in pixels */
  742. {
  743.     PCXHEAD pcxh;
  744.     unsigned char red[256];
  745.     unsigned char green[256];
  746.     unsigned char blue[256];
  747.     int wide;
  748.     int high;
  749.     int bytes;
  750.     int cp;
  751.     int bpp;
  752.  
  753.     if (!PCXreadhead(pcxf, &pcxh)) {
  754.         sprintf(errbuf,"em:graph: Unable to Read Valid PCX Header");
  755.         specerror(errbuf);
  756.     }
  757.     PCXgetpalette(pcxf, &pcxh, red, green, blue);
  758.  
  759.     /* picture size calculation */
  760.     wide = (pcxh.xmax - pcxh.xmin) + 1;
  761.     high = (pcxh.ymax - pcxh.ymin) + 1;
  762.     bytes = pcxh.byteperline;
  763.     cp = pcxh.colorplanes;
  764.     bpp = pcxh.bitperpix;
  765.  
  766.     imagehead(filename,wide,high,emwidth,emheight);
  767.     PCXshowpicture(pcxf, wide, high, bytes, cp, bpp, red, green, blue);
  768.     imagetail();
  769. }
  770.  
  771. /* Microsoft Paint routines */
  772. struct wpnt_1 {
  773.     quarterword id[4];
  774.     halfword width;
  775.     halfword high;
  776.     halfword x_asp;
  777.     halfword y_asp;
  778.     halfword x_asp_prn;
  779.     halfword y_asp_prn;
  780.     halfword width_prn;
  781.     halfword high_prn;
  782.     integer chk_sum;
  783.     halfword chk_head;
  784. };
  785.  
  786. #define WPAINT_1 1
  787. #define WPAINT_2 2
  788.  
  789. void MSP_2_ps(f, wide, high)
  790. FILE *f;
  791. int wide;
  792. int high;
  793. {
  794.     char *line;
  795.     char *l;
  796.     int i;
  797.     int j;
  798.     unsigned char a, b, c;
  799.     int d;
  800.     int width;
  801.     halfword *linelen;
  802.  
  803.     /* an undocumented format - based on a type of run length encoding    */
  804.     /* the format is made up of a list of line lengths, followed by a set */
  805.     /* of lines. Each line is made up of 2 types of entries:              */
  806.     /*     1) A 3 term entry (0 a b): the byte b is repeated a times     */
  807.     /*    2) A variable length entry (a xxxx....xxxx): a bytes are read */
  808.     /*       from the file.                                             */
  809.     /* These entries are combined to build up a line                      */
  810.  
  811.     width = tobyte(wide)*8;
  812.  
  813.     /* output the postscript image size preamble */
  814.     cmdout("/picstr");
  815.     numout((integer)tobyte(wide));
  816.     cmdout("string def");
  817.  
  818.     numout((integer)width);
  819.     numout((integer)high);
  820.     numout((integer)1);
  821.  
  822.     cmdout("[");
  823.     numout((integer)width);
  824.     numout((integer)0);
  825.     numout((integer)0);
  826.     numout((integer)-high);
  827.     numout((integer)0);
  828.     numout((integer)0);
  829.     cmdout("]");
  830.  
  831.     nlcmdout("{currentfile picstr readhexstring pop} image");
  832.  
  833.     fseek(f, 32, SEEK_SET);
  834.  
  835.     /* read in the table of line lengths */    
  836.     linelen = (halfword *) mymalloc((integer)sizeof(halfword) * high);
  837.     for (i = 0; i < high; i++) {
  838.         linelen[i] = readhalfword(f);
  839.         if (feof(f))
  840.             return;
  841.     }
  842.  
  843.     line = (char *) mymalloc((integer)tobyte(wide));
  844.     for (i = 0; i < high; i++) {
  845.         memset(line, 0xff, tobyte(wide));
  846.         l = line;
  847.         if (linelen[i] != 0) {
  848.             d = linelen[i];
  849.             while (d) {
  850.                 a = fgetc(f);
  851.                 d--;
  852.                 if (a == 0) {
  853.                     b = fgetc(f);
  854.                     c = fgetc(f);
  855.                     d -= 2;
  856.                     for (j = 0; j < b; j++)
  857.                         *l++ = c;
  858.                 }
  859.                 else {
  860.                     for (j = 0; j < a; j++)
  861.                         *l++ = fgetc(f);
  862.                     d -= j;
  863.                 }
  864.             }
  865.         }
  866.         newline();
  867.         mhexout(line,(long)tobyte(wide));
  868.     }
  869.     free(linelen);
  870.     free(line);
  871. }
  872.  
  873. void MSP_1_ps(f, wide, high)
  874. FILE *f;
  875. int wide;
  876. int high;
  877. {
  878.     char *line;
  879.     int i;
  880.     int width;
  881.  
  882.     width = tobyte(wide)*8;
  883.     /* an partly documented format - see The PC Sourcebook                */
  884.     /* the format is made up of a simple bitmap.                          */
  885.  
  886.     /* output the postscript image size preamble */
  887.     cmdout("/picstr");
  888.     numout((integer)tobyte(wide));
  889.     cmdout("string def");
  890.  
  891.     numout((integer)width);
  892.     numout((integer)high);
  893.     numout((integer)1);
  894.  
  895.     cmdout("[");
  896.     numout((integer)width);
  897.     numout((integer)0);
  898.     numout((integer)0);
  899.     numout((integer)-high);
  900.     numout((integer)0);
  901.     numout((integer)0);
  902.     cmdout("]");
  903.  
  904.     nlcmdout("{currentfile picstr readhexstring pop} image");
  905.  
  906.     fseek(f, 32, SEEK_SET);
  907.  
  908.     line = (char *) mymalloc((integer)tobyte(wide));
  909.     for (i = 0; i < high; i++) {
  910.         fread(line, 1, tobyte(wide), f);
  911.         newline();
  912.         mhexout(line,(long)tobyte(wide));
  913.     }
  914.     free(line);
  915. }
  916.  
  917.  
  918. void mspgraph(f,filename,emwidth,emheight)
  919. FILE *f;
  920. char filename[];
  921. float emwidth, emheight;    /* dimension in pixels */
  922. {
  923.     struct wpnt_1 head;
  924.     int paint_type = 0;
  925.  
  926.         /* read the header of the file and figure out what it is */
  927.     fread(head.id, 1, 4, f);
  928.     head.width = readhalfword(f); 
  929.     head.high = readhalfword(f); 
  930.     head.x_asp = readhalfword(f); 
  931.     head.y_asp = readhalfword(f); 
  932.     head.x_asp_prn = readhalfword(f); 
  933.     head.y_asp_prn = readhalfword(f); 
  934.     head.width_prn = readhalfword(f); 
  935.     head.high_prn = readhalfword(f); 
  936.     head.chk_sum = readinteger(f); 
  937.     head.chk_head = readhalfword(f); 
  938.  
  939.     if (feof(f)) {
  940.         fprintf(stderr, "em:graph: Unable to Read Valid MSP Header\n");
  941.         return;
  942.     }
  943.         
  944.         /* check the id bytes */
  945.     if (!memcmp(head.id, "DanM", 4))
  946.             paint_type = WPAINT_1;
  947.     if (!memcmp(head.id, "LinS", 4))
  948.         paint_type = WPAINT_2;
  949.  
  950.  
  951.     imagehead(filename,head.width,head.high,emwidth,emheight);
  952.     switch (paint_type) {
  953.         case WPAINT_1:
  954.                     MSP_1_ps(f, head.width, head.high);
  955.             break;
  956.                 case WPAINT_2:
  957.                     MSP_2_ps(f, head.width, head.high);
  958.             break;
  959.         default:
  960.             sprintf(errbuf, "em:graph: Unknown MSP File Type");
  961.             specerror(errbuf);
  962.     }
  963.     imagetail() ;
  964. }
  965.  
  966. /* ------------------------------------------------------------------------ */
  967. /* .BMP file structures */
  968. struct rgbquad {
  969.     char blue;
  970.     char green;
  971.     char red;
  972.     char res;
  973. };
  974.  
  975. struct bitmapinfoheader {
  976.     integer size;
  977.     integer width;
  978.     integer height;
  979.     halfword planes;            /* must be set to 1 */
  980.     halfword bitcount;            /* 1, 4, 8 or 24 */
  981.     integer compression;
  982.     integer sizeimage;
  983.     integer xpelspermeter;
  984.     integer ypelspermeter;
  985.     integer clrused;
  986.     integer clrimportant;
  987. };
  988.  
  989. /* constants for the compression field */
  990. #define RGB 0L
  991. #define RLE8 1L
  992. #define RLE4 2L
  993.  
  994. struct bitmapfileheader {
  995.     char type[2];
  996.     integer size;
  997.     halfword reserved1;
  998.     halfword reserved2;
  999.     integer offbits;
  1000. };
  1001.  
  1002. void rgbread(f, w, b, s)
  1003. FILE *f;
  1004. int b;
  1005. int w;
  1006. char *s;
  1007. {
  1008.     int i;
  1009.  
  1010.     /* set the line to white */
  1011.     memset(s, 0xff, ((w*b)/8)+1); 
  1012.  
  1013.     /* read in all the full bytes */
  1014.     for (i = 0; i < (w * b) / 8; i++)
  1015.         *s++ = fgetc(f);
  1016.  
  1017.     /* read in a partly filled byte */
  1018.     if ((w * b) % 8) {
  1019.         i++;
  1020.         *s++ = fgetc(f);
  1021.     }
  1022.  
  1023.     /* check that we are on a 32 bit boundary; otherwise align */
  1024.     while (i % 4 != 0) {
  1025.         fgetc(f);
  1026.         i++;
  1027.     }
  1028. }
  1029.  
  1030. unsigned rle_dx = 0;    /* delta command horizontal offset */
  1031. unsigned rle_dy = 0;    /* delta command vertical offset */
  1032.  
  1033. /* checked against output from Borland Resource Workshop */
  1034. void rle4read(f, w, b, s)
  1035. FILE *f;
  1036. int b;
  1037. int w;
  1038. char *s;
  1039. {
  1040.     int i;
  1041.     int limit;
  1042.     int ch;
  1043.     unsigned cnt;
  1044.     int hi;
  1045.  
  1046.     limit = (w*b)/8;
  1047.     i = 0;
  1048.     hi = TRUE;
  1049.     /* set the line to white */
  1050.     memset(s, 0xff, limit+1); 
  1051.  
  1052.     if (rle_dy) {
  1053.         rle_dy--;
  1054.         return;
  1055.     }
  1056.  
  1057.     if (rle_dx) {
  1058.         for ( ; rle_dx>1; rle_dx-=2) {
  1059.         s++;
  1060.         i++;
  1061.         }
  1062.         if (rle_dx)
  1063.             hi = FALSE;
  1064.     }
  1065.  
  1066.     while (i<=limit) {
  1067.         cnt = fgetc(f);
  1068.         ch  = fgetc(f);
  1069.         if (cnt == 0) { /* special operation */
  1070.         switch(ch) {
  1071.             case 0:    /* EOL */
  1072.             return;    /* this is our way out */
  1073.             case 1:    /* End of Bitmap */
  1074.                 return;
  1075.             case 2:    /* Delta */  /* untested */
  1076.             rle_dx = fgetc(f) + i*2 + (hi ? 1 : 0);
  1077.             rle_dy = fgetc(f);
  1078.             return;
  1079.             default:    /* next cnt bytes are absolute */
  1080.                 /* must be aligned on word boundary */
  1081.             if (!hi)
  1082.                 fprintf(stderr,"em:graph: RLE4 absolute is not byte aligned\n");
  1083.             for (cnt = ch; cnt>0 && i<=limit; cnt-=2) {
  1084.                     i++;
  1085.                 *s++ = fgetc(f);
  1086.             }
  1087.             if (ch % 4)    /* word align file */
  1088.                 (void)fgetc(f);
  1089.           }
  1090.         }
  1091.         else {   /* cnt is repeat count */
  1092.         if (!hi) {   /* we are about to place the low 4 bits */
  1093.             ch = ((ch>>4)&0x0f) | ((ch<<4)&0xf0); /* swap order */
  1094.             i++;
  1095.             *s++ = (*s & 0xf0) | (ch & 0x0f);
  1096.             hi = TRUE;
  1097.             cnt--;
  1098.         }
  1099.         /* we are about to place the high 4 bits */
  1100.         for ( ; cnt>1 && i<=limit ; cnt-=2) { /* place the whole bytes */
  1101.             i++;
  1102.             *s++ = ch;
  1103.             }
  1104.         if (cnt) { /* place the partial byte */
  1105.             *s = (*s & 0x0f) | (ch & 0xf0);
  1106.             hi = FALSE;
  1107.         }
  1108.         }
  1109.       }
  1110. }
  1111.   
  1112. /* untested */
  1113. void rle8read(f, w, b, s)
  1114. FILE *f;
  1115. int b;
  1116. int w;
  1117. char *s;
  1118. {
  1119.     int i;
  1120.     int limit;
  1121.     int ch;
  1122.     unsigned cnt;
  1123.  
  1124.     limit = (w*b)/8;
  1125.     i = 0;
  1126.     /* set the line to white */
  1127.     memset(s, 0xff, limit+1); 
  1128.  
  1129.     if (rle_dy) {
  1130.         rle_dy--;
  1131.         return;
  1132.     }
  1133.  
  1134.     if (rle_dx) {
  1135.         for ( ; rle_dx > 0; rle_dx--) {
  1136.         s++;
  1137.         i++;
  1138.         }
  1139.     }
  1140.  
  1141.     while (i<=limit) {
  1142.         cnt = fgetc(f);
  1143.         ch  = fgetc(f);
  1144.         if (cnt == 0) { /* special operation */
  1145.         switch(ch) {
  1146.             case 0:    /* EOL */
  1147.             return;    /* this is our way out */
  1148.             case 1:    /* End of Bitmap */
  1149.             return;
  1150.             case 2:    /* Delta */  /* untested */
  1151.             rle_dx = fgetc(f) + i;
  1152.             rle_dy = fgetc(f);
  1153.             return;
  1154.             default:    /* next cnt bytes are absolute */
  1155.             for (cnt = ch; cnt>0 && i<=limit; cnt--) {
  1156.                     i++;
  1157.                 *s++ = fgetc(f);
  1158.                 }
  1159.             if (ch % 2)    /* word align file */
  1160.                 (void)fgetc(f);
  1161.         }
  1162.         }
  1163.         else { /* cnt is repeat count */
  1164.         for ( ; cnt>0 && i<=limit; cnt--) {
  1165.             i++;
  1166.             *s++ = ch;
  1167.         }
  1168.         }
  1169.     }
  1170. }
  1171.  
  1172. void bmpgraph(f,filename,emwidth,emheight)
  1173. FILE *f;
  1174. char filename[];
  1175. float emwidth, emheight;    /* dimension in pixels */
  1176. {
  1177.     struct bitmapfileheader bmfh;
  1178.     struct bitmapinfoheader bmih;
  1179.  
  1180.     unsigned char isblack[256];
  1181.     unsigned char rr;
  1182.     unsigned char gg;
  1183.     unsigned char bb;
  1184.     unsigned char c = 0;
  1185.  
  1186.     char *line;
  1187.     char *pshexa;
  1188.  
  1189.     int clrtablesize;
  1190.     int i;
  1191.     int j;
  1192.  
  1193.     unsigned char omask;
  1194.     int oroll;
  1195.  
  1196.     unsigned char emask = 0;
  1197.     integer ewidth = 0;
  1198.     int isOS2;
  1199.  
  1200.         /* read the header of the file */
  1201.     fread(bmfh.type, 1, 2, f);
  1202.     bmfh.size = readinteger(f);
  1203.     bmfh.reserved1 = readhalfword(f);
  1204.     bmfh.reserved2 = readhalfword(f);
  1205.     bmfh.offbits = readinteger(f);
  1206.     if (feof(f)) {
  1207.         sprintf(errbuf, "em:graph: Unable to Read Valid BMP Header\n");
  1208.         specerror(errbuf);
  1209.         return;
  1210.     }
  1211.  
  1212.     bmih.size = readinteger(f);
  1213.     if (bmih.size == 12) { /* OS2 bitmap */
  1214.         isOS2 = TRUE;    
  1215.         bmih.width = readhalfword(f);
  1216.         bmih.height = readhalfword(f);
  1217.         bmih.planes = readhalfword(f);
  1218.         bmih.bitcount = readhalfword(f);
  1219.         /* the following don't exist in OS2 format so fill with 0's */
  1220.         bmih.compression = RGB;
  1221.         bmih.sizeimage = 0;
  1222.         bmih.xpelspermeter = 0;
  1223.         bmih.ypelspermeter = 0;
  1224.         bmih.clrused = 0;
  1225.         bmih.clrimportant = 0;
  1226.     }
  1227.     else { /* Windows bitmap */
  1228.         isOS2 = FALSE;    
  1229.         bmih.width = readinteger(f);
  1230.         bmih.height = readinteger(f);
  1231.         bmih.planes = readhalfword(f);
  1232.         bmih.bitcount = readhalfword(f);
  1233.         bmih.compression = readinteger(f);
  1234.         bmih.sizeimage = readinteger(f);
  1235.         bmih.xpelspermeter = readinteger(f);
  1236.         bmih.ypelspermeter = readinteger(f);
  1237.         bmih.clrused = readinteger(f);
  1238.         bmih.clrimportant = readinteger(f);
  1239.     }
  1240.  
  1241.     if (feof(f)) {
  1242.         sprintf(errbuf, "em:graph: Unable to Read Valid BMP Info");
  1243.         specerror(errbuf);
  1244.         return;
  1245.     }
  1246.  
  1247.     if (memcmp(bmfh.type, "BM", 2)) {
  1248.         sprintf(errbuf, "em:graph: Unknown BMP File Type");
  1249.         specerror(errbuf);
  1250.         return;
  1251.     }
  1252.  
  1253.     if ((bmih.compression == RLE4) && (bmih.bitcount != 4)) {
  1254.         sprintf(errbuf, "em:graph: Can't do BMP RLE4 with %d bits per pixel",
  1255.             bmih.bitcount);
  1256.         specerror(errbuf);
  1257.         return;
  1258.     }
  1259.  
  1260.     if ((bmih.compression == RLE8) && (bmih.bitcount != 8)) {
  1261.         sprintf(errbuf, "em:graph: Can't do BMP RLE8 with %d bits per pixel\n",
  1262.             bmih.bitcount);
  1263.         specerror(errbuf);
  1264.         return;
  1265.     }
  1266.  
  1267.     imagehead(filename,(int)bmih.width,(int)bmih.height,emwidth,emheight);
  1268.  
  1269.     /* determine the size of the color table to read */
  1270.     clrtablesize = 0;
  1271.     if (bmih.clrused == 0) {
  1272.         switch (bmih.bitcount) {
  1273.             case 1:
  1274.                 clrtablesize = 2;
  1275.                 break;
  1276.             case 4:
  1277.                 clrtablesize = 16;
  1278.                 break;
  1279.             case 8:
  1280.                 clrtablesize = 256;
  1281.                 break;
  1282.             case 24:
  1283.                 break;
  1284.         }
  1285.     }
  1286.         else
  1287.         clrtablesize = bmih.clrused;
  1288.  
  1289.     /* read in the color table */
  1290.     for (i = 0; i < clrtablesize; i++) {
  1291.         bb = fgetc(f);
  1292.         gg = fgetc(f);
  1293.         rr = fgetc(f);
  1294.         isblack[i] = (rr < 0xff) || (gg < 0xff) || (bb < 0xff);
  1295.         if (!isOS2)
  1296.             (void) fgetc(f);
  1297.     }
  1298.  
  1299.     line = (char *) mymalloc((integer)((bmih.width * bmih.bitcount) / 8) + 1);
  1300.     pshexa = (char *) mymalloc((integer)tobyte(bmih.width));
  1301.  
  1302.     /* output the postscript image size preamble */
  1303.     cmdout("/picstr");
  1304.     numout((integer)tobyte(bmih.width));
  1305.     cmdout("string def");
  1306.  
  1307.     numout((integer)bmih.width);
  1308.     numout((integer)bmih.height);
  1309.     numout((integer)1);
  1310.  
  1311.     cmdout("[");
  1312.     numout((integer)bmih.width);
  1313.     numout((integer)0);
  1314.     numout((integer)0);
  1315.     numout((integer)bmih.height);
  1316.     numout((integer)0);
  1317.     numout((integer)bmih.height);
  1318.     cmdout("]");
  1319.  
  1320.     nlcmdout("{currentfile picstr readhexstring pop} image");
  1321.  
  1322.     if (bmih.bitcount == 1) {
  1323.         if (bmih.width%8)
  1324.             emask = (1<<(8-(bmih.width%8)))-1;    /* mask for edge of bitmap */
  1325.         else
  1326.             emask = 0;
  1327.         ewidth = tobyte(bmih.width);
  1328.     }
  1329.  
  1330.     /* read in all the lines of the file */
  1331.     for (i = 0; i < bmih.height; i++) {
  1332.         memset(pshexa,0xff,tobyte(bmih.width));
  1333.         switch (bmih.compression) {
  1334.             case RGB:
  1335.             rgbread(f, (int) bmih.width, (int) bmih.bitcount, line);
  1336.             break;
  1337.             case RLE4:
  1338.             rle4read(f, (int) bmih.width, (int) bmih.bitcount, line);
  1339.             break;
  1340.             case RLE8:
  1341.             rle8read(f, (int) bmih.width, (int) bmih.bitcount, line);
  1342.             break;
  1343.             default:
  1344.             sprintf(errbuf,"em:graph: Unknown BMP compression\n");
  1345.             specerror(errbuf);
  1346.             return;
  1347.         }
  1348.  
  1349.         omask = 0x80;
  1350.         oroll = 7;
  1351.  
  1352.         if (bmih.bitcount == 1) {
  1353.             if (isblack[0])
  1354.             for (j = 0; j < ewidth ; j++)
  1355.                 pshexa[j] = line[j];
  1356.             else
  1357.             for (j = 0; j < ewidth ; j++)
  1358.                 pshexa[j] = ~line[j];
  1359.             pshexa[ewidth-1] |= emask;
  1360.         }
  1361.         else {
  1362.             for (j = 0; j < bmih.width; j++) {
  1363.             switch (bmih.bitcount) {
  1364.                 case 4:
  1365.                     c = line[j>>1];
  1366.                     if (!(j&1))
  1367.                         c >>= 4;
  1368.                     c = isblack[ c & 0x0f ];
  1369.                     break;
  1370.                 case 8:
  1371.                     c = isblack[ (int)(line[j]) ];
  1372.                     break;
  1373.                 case 24:
  1374.                     rr = line[j*3];
  1375.                     gg = line[j*3+1];
  1376.                     bb = line[j*3+2];
  1377.                     c = (rr < 0xff) || (gg < 0xff) || (bb < 0xff);
  1378.                     break;
  1379.             }
  1380.             if (c) 
  1381.                 pshexa[j/8] &= ~omask;
  1382.             else
  1383.                 pshexa[j/8] |= omask;
  1384.             oroll--;
  1385.             omask >>= 1;
  1386.             if (oroll < 0) {
  1387.                 omask = 0x80;
  1388.                 oroll = 7;
  1389.             }
  1390.             }
  1391.         }
  1392.         newline();
  1393.         mhexout(pshexa,(long)tobyte(bmih.width));
  1394.     }
  1395.     imagetail() ;
  1396.     free(pshexa);
  1397.     free(line);
  1398. }
  1399. /* ------------------------------------------------------------------------ */
  1400.  
  1401. #define PCX 0
  1402. #define MSP 1
  1403. #define BMP 2
  1404. char *extarr[]=
  1405. { ".pcx", ".msp", ".bmp", NULL };
  1406.  
  1407. void emgraph(filename,emwidth,emheight)
  1408. char filename[];
  1409. float emwidth, emheight;    /* dimension in pixels */
  1410. {
  1411.     char fname[80];
  1412.     int filetype;
  1413.     FILE *f;
  1414.     char *env;
  1415.     char id[4];
  1416.     int i;
  1417.  
  1418.     strcpy(fname, filename);
  1419.  
  1420.     /* find the file */
  1421.     f = search(figpath, fname, READBIN);
  1422.     if (f == (FILE *)NULL) {
  1423.            if ( (env = getenv("DVIDRVGRAPH")) != NULL )
  1424.         f = search(env,filename,READBIN);
  1425.     }
  1426.     /* if still haven't found it try adding extensions */
  1427.     if (f == (FILE *)NULL) {
  1428.         i = 0;
  1429.         while (extarr[i] != NULL) {
  1430.         strcpy(fname, filename);
  1431.         strcat(fname, extarr[i]);
  1432.         f = search(figpath, fname, READBIN);
  1433.         if (f == (FILE *)NULL) {
  1434.                 if ( (env = getenv("DVIDRVGRAPH")) != NULL )
  1435.             f = search(env,filename,READBIN);
  1436.         }
  1437.         if (f != (FILE *)NULL)
  1438.             break;
  1439.         i++;
  1440.         }
  1441.     }
  1442.  
  1443.     filetype = -1;
  1444.     if (f != (FILE *)NULL) {
  1445.         for (i=0; i<4; i++) {
  1446.         id[i] = readquarterword(f);
  1447.         }
  1448.         if ( (id[0] == 0x0a) && (id[2] == 0x01) )
  1449.         filetype = PCX;
  1450.         if (!memcmp(id, "DanM", 4))
  1451.         filetype = MSP;
  1452.         if (!memcmp(id, "LinS", 4))
  1453.         filetype = MSP;
  1454.         if (!memcmp(id, "BM", 2))
  1455.         filetype = BMP;
  1456.         fseek(f, 0L, SEEK_SET);
  1457.     }
  1458.  
  1459.     switch (filetype) {
  1460.         case PCX:
  1461.             pcxgraph(f, fname, emwidth, emheight);
  1462.             break;
  1463.         case MSP:
  1464.             mspgraph(f, fname, emwidth, emheight);
  1465.             break;
  1466.         case BMP:
  1467.             bmpgraph(f, fname, emwidth, emheight);
  1468.             break;
  1469.         default:
  1470.             sprintf(fname,"em:graph: %s: File not found", filename);
  1471.             error(fname);
  1472.     }
  1473.     if (f != (FILE *)NULL)
  1474.         fclose(f);
  1475. }
  1476.  
  1477. #else
  1478. void emspecial(p)
  1479. char *p ;
  1480. {
  1481.     sprintf(errbuf,"emTeX specials not compiled in this version");
  1482.     specerror(errbuf);
  1483. }
  1484. #endif /* EMTEX */
  1485.